package br.unifor.cct.mia.xover;

import br.unifor.cct.mia.evolutionary.Genotype;
import br.unifor.cct.mia.evolutionary.Individual;
import br.unifor.cct.mia.ga.Ga;
import br.unifor.cct.mia.util.Methods;

public class BasicXOverMutation extends XOver {

	private void xover(Ga ga) {
        if (ga.configurations.getNvars() > 1) {
            int point = (ga.configurations.getNvars() == 2?1:Methods.randIntValue(1, ga.configurations.getNvars()));
            int rest = ga.configurations.getNvars() - point;
            
            Genotype filho = new Genotype(ga.configurations);        	       	
            filho.setFitness(0);
            filho.setSelectProbability(0);        
            
            System.arraycopy(((Genotype)ga.population[one]).getGene(), 0, filho.getGene(), 0, point-1);
            System.arraycopy(((Genotype)ga.population[two]).getGene(), point, filho.getGene(), point, rest);
                        
            //Mutation            
            for (int j = 0; j < ga.configurations.getNvars(); j++) {
            	double x = Methods.randDoubleValue(0, 1);
	            if (x < ga.configurations.getPmutation()) {
	                double lbound = filho.getLower(j);
	                double ubound = filho.getUpper(j);
	                
	                if (filho.getInteger(j))
	                	filho.setGene(Methods.randIntValue((int)lbound, (int)ubound), j);
	                else
	                	filho.setGene(Methods.randDoubleValue(lbound,ubound), j);
	            }
            }
            
            replaceWorst(ga,filho);
        }
	}
	
	private void replaceWorst(Ga ga, Genotype filho ) {
		Individual[] population = ga.population;
		 
		int minPos = 0;
		double minVal = Integer.MAX_VALUE;
		for ( int i=1; i<ga.configurations.getPopsize(); i++ ) {			
			if ( population[i].fitness>=0 && population[i].fitness<minVal ) {
				minPos = i;
				minVal = population[i].fitness;
			}			
		}		
		
		System.arraycopy(filho.getGene(), 0, ((Genotype)population[minPos]).getGene(), 0, filho.getGene().length);
		population[minPos].setFitness(-1);
	}
	
	public Object execute(Object value) {
    	Object[] o = (Object[])value;
		Ga ga = (Ga)o[0];
		
		xover(ga);
		return ga.population;
	}
}